package com.ufun.financegateway.controller;

import com.ufun.financegateway.dto.*;
import com.ufun.financegateway.util.RSAUtils;
import com.ufun.financegateway.util.Sha256Util;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author BlendLiu
 * @date 2021/4/20 9:15
 */
@RestController
@RequestMapping("/netPay")
@Api(tags = "付款")
public class IndexController {

    //设备用的签名秘钥
    private String machinePrivateKeyForSign;

    //给设备加密用的秘钥
    private String machinePrivateKeyForEncrypt;



    /**
     * 招行公钥
     *  回调方法解密
     */
    private String bankPublicKey;

    //招行私钥
    private String bankPrivateKey;

    @GetMapping("/hello")
    public String hello(){
        return "hello word";
    }

    @ApiOperation("付款请求")
    @PostMapping("pay")
    public NetPayResponseDto netPay(@RequestBody @Valid NetPayRequestDto netPayRequestDto)  {
        NetPayRequestDataDto requestDateDto = netPayRequestDto.getReqData();

        String sha256 = this.getSHA256Sign(requestDateDto, machinePrivateKeyForSign);
        String sign = netPayRequestDto.getSign();

        NetPayResponseDto payResponseDto = new NetPayResponseDto();
        NetPayResponseDataDto responseDataDto = new NetPayResponseDataDto();


        if (true) {
            responseDataDto.setRspCode("000");
            responseDataDto.setRspMsg("交易已收妥");
        } else {
            //签名不通过
            responseDataDto.setRspCode("207");
            responseDataDto.setRspMsg("签名错误");
        }

        responseDataDto.setAmount(requestDateDto.getAmount() + "");
        responseDataDto.setPayTime("2016-12-12 10:00:00");
        responseDataDto.setSerialNo("2016062310143099");
        responseDataDto.setOuterOrderNo(requestDateDto.getOuterOrderNo());

        String bankSign = getSHA256Sign(responseDataDto, "");
        String decrypt = RSAUtils.encrypt(bankSign, machinePrivateKeyForEncrypt);
        payResponseDto.setSign(decrypt);
        payResponseDto.setSignType("SHA-256");
        payResponseDto.setCharset("UTF-8");
        payResponseDto.setRspData(responseDataDto);
        payResponseDto.setVersion("1.0");

        return payResponseDto;

    }

    @ApiOperation("查询交易状态")
    @PostMapping("status")
    public PayStatusResponseDto payStatus(@RequestBody @Valid PayStatusRequestDto payStatusRequestDto) {

        PayStatusRequestDataDto reqData = payStatusRequestDto.getReqData();
        String sign = payStatusRequestDto.getSign();

        String sha256 = this.getSHA256Sign(reqData, machinePrivateKeyForSign);

        PayStatusResponseDto payStatusResponseDto = new PayStatusResponseDto();
        PayStatusResponseDataDto responseDataDto = new PayStatusResponseDataDto();

        if (!sign.equals(sha256)) {
            responseDataDto.setRspCode("207");
            responseDataDto.setRspMsg("签名错误");
        } else {
            responseDataDto.setRspCode("000");
            responseDataDto.setRspMsg("原交易处理成功");
        }

        responseDataDto.setAmount("");
        responseDataDto.setDiscountAmount("");
        responseDataDto.setDiscountFlag("");
        responseDataDto.setFeeAmt("");
        responseDataDto.setOrigRspCode("");
        responseDataDto.setOrigRspMsg("");
        responseDataDto.setOrigSerialNo("");
        responseDataDto.setSettleDate("");


        payStatusResponseDto.setRspData(responseDataDto);
        String sha256Sign = this.getSHA256Sign(responseDataDto, "");
        RSAUtils.encrypt(sha256Sign, machinePrivateKeyForEncrypt);

        payStatusResponseDto.setSign(sha256Sign);
        payStatusResponseDto.setSignType("SHA-256");
        payStatusResponseDto.setVersion("1.0");
        payStatusResponseDto.setCharset("UTF-8");

        return payStatusResponseDto;

    }

    @ApiOperation("异步回调")
    @PostMapping("notice")
    public NoticeResponseDto payNotice(@RequestBody CmbBankNoticeRequestDto cmbBankNoticeRequestDto) {

        String noticeRequestDtoSign = cmbBankNoticeRequestDto.getSign();
        String decrypt = RSAUtils.decrypt(noticeRequestDtoSign, bankPublicKey);

        CmbBankNoticeRequestDataDto requestDataDto = cmbBankNoticeRequestDto.getNoticeData();
        //这里解密用要的key 跟 签名用的 key 都是招行给的公钥
        String sha256Sign = this.getSHA256Sign(requestDataDto, "");

        if (sha256Sign.equals(decrypt)) {
            //与银行验签成功
            
            //设备回调地址
            String noticeUrl = "";

            NoticeResponseDto responseDto = new NoticeResponseDto();
            NoticeResponseDataDto responseDataDto = new NoticeResponseDataDto();

            responseDataDto.setAmount(requestDataDto.getAmount());
            responseDataDto.setDiscountAmount(requestDataDto.getDiscountAmount());
            responseDataDto.setDiscountFlag(requestDataDto.getDiscountFlag());
            responseDataDto.setFeeAmt(requestDataDto.getFee_amt());
            responseDataDto.setMerchantSerialNo(requestDataDto.getMerchantSerialNo());
            responseDataDto.setNoticeSerialNo(requestDataDto.getNoticeSerialNo());
            responseDataDto.setRequestTime(requestDataDto.getDateTime());
            responseDataDto.setRspCode("000");
            responseDataDto.setRspMsg("收款成功");
            responseDataDto.setSerialNo(requestDataDto.getBankSerialNo());
            responseDataDto.setSettleDate(requestDataDto.getSettleDate());

            responseDto.setNoticeData(responseDataDto);
            responseDto.setCharset("UTF-8");
            responseDto.setVersion("1.0");
            responseDto.setSignType("RSA");
            String responseSign = this.getSHA256Sign(responseDataDto, "");
            String encrypt = RSAUtils.encrypt(responseSign, machinePrivateKeyForEncrypt);
            responseDto.setSign(encrypt);
            
            return responseDto;

        } 
        return null;
    }


    public String getSHA256Sign(Object obj, String key) {

        Field[] fields = obj.getClass().getDeclaredFields();
        List<Field> fieldList = Arrays.stream(fields).sorted(Comparator.comparing(f -> f.getName().toLowerCase())).collect(Collectors.toList());

        StringJoiner stringJoiner = new StringJoiner("&");

        for (Field field : fieldList) {
            try {
                field.setAccessible(true);
                Object value = Optional.ofNullable(field.get(obj)).orElse("");
                stringJoiner.add(field.getName() + "=" + value);

            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        if (!StringUtils.isEmpty(key)){
            stringJoiner.add(key);
        }
        String strToSign = stringJoiner.toString();
        return Sha256Util.getSHA256(strToSign);
    }

}
